package framework.web.rpc;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import framework.web.rpc.adapter.IAdapter;

/**
 * 这里要处理的：
 * 1. 解析请求的json数据，并且返回执行结果
 * 
 * @version $Revision$ $Date$
 * @author Base
 * @since 1.0
 */
public class JsonRpcBridge {
	/***
	 * 执行JSON-RPC请求的方法，并返回JSON格式的结果
	 * @param request
	 * @param json 请求的json字串
	 * @param adapter 输出转换适配器，如果没有，则直接使用json规则转出
	 * @return
	 */
	public static String exec(HttpServletRequest request, String json, IAdapter adapter) {
		try {
			json = decodeUnicodeHtm(json);
			JSONObject oJson = new JSONObject(json);
			String[] action = oJson.getString("action").split("[.]");
			String k = action[0], method = action[1];
			JSONArray params = oJson.getJSONArray("params");
			// 对Map和List的注册和获取做特殊处理，因为集合中的每个元素可能是不同的对象，
			// 因此注册名必须区分开来
			Object o = JsonRpcRegister.getObject(k);
			if (null != o) {
				// 设置request
				try {
					o.getClass().getMethod("setRequest", HttpServletRequest.class).invoke(o, request);
				} catch (Exception e) {
					e.printStackTrace();
				}
				// 处理具体逻辑
				Method[] methods = o.getClass().getMethods();
				Class[] types;
				Class type;
				String typeName;
				Object[] oParams = new Object[params.length()];
				for (Method m : methods) {
					types = m.getParameterTypes();
					if(m.getName().equals(method) && params.length() == types.length){
						for (int i = 0; i < types.length; i++) {
							type = types[i];
							oParams[i] = params.get(i);
							if(!type.isInstance(params.get(i))){
								typeName = type.getName();
								if(typeName.equals("java.util.Integer")){
									oParams[i] = (Integer)Integer.parseInt(oParams[i].toString());
								}else if(typeName.equals("java.util.Float")){
									oParams[i] = (Float)Float.parseFloat(oParams[i].toString());
								}else if(typeName.equals("java.math.BigDecimal")){
									oParams[i] = new BigDecimal(oParams[i].toString());
								}else if(typeName.equals("java.lang.String")){
									oParams[i] = oParams[i].toString();
								}
							}
						}
						types = null;
						params = null;
						try {
							Object result = m.invoke(o, oParams);
							oParams = null;
							if (null != result) {
								if (adapter == null)
									return new JSONObject(result).toString();
								return adapter.translate(result);
							}
							return "{result: true}";
						} catch (Exception e) {
							e.printStackTrace();
						}
						break;
					}
				}
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return "{result: false}";
	}

	/**
	 * 解析请求的json数据，并从缓冲中取到对应的对象
	 * @param json
	 * @return
	 */
	public static Object getObject(String json) {
		if (json == null || json.trim().length() == 0)
			return null;
		try {
			json = decodeUnicodeHtm(json);
			JSONObject o = new JSONObject(json);
			return JsonRpcRegister.getObject(o.getString("action").split("[.]")[0]);
		} catch (JSONException e) {
			e.printStackTrace();
		}		
		return null;
	}

	//--------------------------------------------------------------------------------------------
	/***
	 * 解码html方式编码的中文汉字
	 * ，例如将：
	 *  "&#24322;&#24120;" 解码为 "异常" 
	 * 符合的汉字正则表达式范围是：[\u4E00-\u9FA5]
	 * @param szStr
	 * @return
	 */
	public static String decodeUnicodeHtm(String szStr) {
		Pattern p = Pattern.compile("&#(\\d+);", Pattern.MULTILINE);
		Matcher m = p.matcher(szStr);
		StringBuffer buf = new StringBuffer();
		while (m.find())
			m.appendReplacement(buf, (char) Integer.valueOf(m.group(1)).intValue() + "");
		m.appendTail(buf);
		return buf.toString();
	}

	/***
	 * 编码码字符串为html方式编码的中文汉字，例如将：
	 *  "异常" 编码为 "&#24322;&#24120;" 
	 * 符合的汉字正则表达式范围是：[\u4E00-\u9FA5]
	 * @param szStr
	 * @return
	 */
	public static String encodeUnicodeHtm(String szStr) {
		Pattern p = Pattern.compile("[\u4E00-\u9FA5]", Pattern.MULTILINE);
		Matcher m = p.matcher(szStr);
		StringBuffer buf = new StringBuffer();
		while (m.find())
			m.appendReplacement(buf, "&#" + (int) m.group(0).toCharArray()[0] + ";");
		m.appendTail(buf);
		return buf.toString();
	}
}
